﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using MethodWorx.CMS.Content;
using MethodWorx.CMS.Web;
using System.Xml;
using MethodWorx.CMS.TemplateLanguage.Properties;
using MethodWorx.CMS.TemplateLanguage.Design;

namespace MethodWorx.CMS.TemplateLanguage.Parsers
{
    public class ContentPropertyParser : IParser, IDesignable, IEditable, IMetaParser
    {
        [Property]
        public string Tag { get; set; }
        [ContentTemplateProperty]
        public string Template { get; set; }
        [ContentTemplatePropertyPropertyAttribute("Template", Alias="Name")]
        public string PropertyName { get; set; }
        [Property]
        public int? Index { get; set; }
        [Property]
        public bool Editable { get; set; }
        [Property(Alias="Class")]
        public string CssClass { get; set; }

        public object Parse(CmsRequestContext context, IEnumerable<object> stack, Dictionary<string, object> parameters)
        {
            var page = stack.OfType<MethodWorx.CMS.Content.Page>().FirstOrDefault();
            if (page == null)
                throw new Exception("No page on the stack");
            else
            {
                //
                //  ok, find the property
                var contentItem = this.GetContentItem(page, stack);
                if (contentItem != null)
                {
                    PageProperty found = null;
                    if (context.Preview)
                        found = contentItem.Properties.FirstOrDefault(p => p.Name.ToLower() == this.PropertyName.ToLower());
                    else
                        found = contentItem.PublishedProperties.FirstOrDefault(p => p.Name.ToLower() == this.PropertyName.ToString().ToLower());

                    if (found != null && found.Value != null)
                    {
                        if (found.Value.IsNull() || found.Value.IsEmpty())
                            return null;

                        return GetNodeValue(found.Value, parameters);
                    }
                    else
                    {
                        if (this.PropertyName.ToLower() == "datepublished")
                            return GetNodeValue(contentItem.DatePublished, parameters);
                        else if (this.PropertyName.ToLower() == "datecreated")
                            return GetNodeValue(contentItem.DateCreated, parameters);
                        else if (this.PropertyName.ToLower() == "name")
                            return GetNodeValue(contentItem.Name, parameters);
                    }
                }
            }

            return null;
        }

        public object GetNodeValue(object property, Dictionary<string, object> parameters)
        {
            if (string.IsNullOrEmpty(this.Tag))
            {
                return property;
            }
            else
            {
                //var val = tag + property.Value.ToString() + "</tag>";
                var result = new HtmlResult();
                result.SetTag(this.Tag);
                result.Content = property;
                foreach (string parameter in parameters.Keys)
                {
                    result.AddAttribute(parameter, parameters[parameter].ToString());
                }
                return result;
            }
        }

        private ContentItem GetContentItem(MethodWorx.CMS.Content.Page page, IEnumerable<object> stack)
        {
            if (this.Index.HasValue)
            {
                var contentItems = page.ChildContent.Select(c => c);
                if (!string.IsNullOrEmpty(this.Template))
                    contentItems = contentItems.Where(c => c.Template.Name.ToLower() == this.Template.ToLower());

                contentItems = contentItems.Skip(this.Index.Value).Take(1);
                return contentItems.FirstOrDefault();
            }
            else
            {
                var item = 
                    stack.OfType<ContentItem>().Where(
                        c => string.IsNullOrEmpty(this.Template) || this.Template.ToLower() == c.Template.Name.ToLower()).
                        LastOrDefault();

                if(item == null)
                    item = page.ChildContent.Where(c => string.IsNullOrEmpty(this.Template) || this.Template.ToLower() == c.Template.Name.ToLower()).
                        FirstOrDefault();

                return item;
            }
        }

        public string Name
        {
            get { return "Property"; }
        }

        public string Namespace
        {
            get { return "Content"; }
        }

        public string[] Parameters
        {
            get
            {
                return new string[]
                {
                    "Template",
                    "Editable",
                    "Name",
                    "Index",
                    "Tag"
                };
            }
        }

        public void Design(IDesigner designer)
        {
            if (!string.IsNullOrEmpty(this.Tag))
            {
                designer.AddControl("Content:Property")
                    .AddContentBeforeChildren("<" + this.Tag + " class=\"" + (this.CssClass ?? "") + "\">" +
                                              (this.Template ?? "") + ":" + (this.PropertyName ?? ""))
                    .AddContentAfterChildren("</" + this.Tag + ">");

            }
            else
            {
                designer.AddControl("Content:Property")
                    .AddContentBeforeChildren("<contentProperty>" + this.Template + ":" + this.PropertyName + "</contentProperty>");
            }
        }

        public void Edit(IEditor editor)
        {
            //
            //  ok, setup the editor for for the current page
            //  and the current content
            var contentItem = this.GetContentItem(editor.CurrentPage, editor.Stack);
            if (contentItem != null)
            {
                editor.AddEditor(this.PropertyName, contentItem);
            }
        }

        public string GetDescription()
        {
            return "Finds a content item by the specified filters";
        }

        public ParserMetaParameter[] GetParameters(Stack<object> stack, ParserMetaParameter[] parameters)
        {
            return parameters;
        }
    }
}
